<?php
namespace Libraries;
use Resources\Config as Config,Resources\RunException as RunException;
class Mysql{
    protected $port = 3306, $column = '*', $distinct = false, $tables = array(), $joins = null,
        $joinsType = null, $joinsOn = array(), $criteria = array(), $groupBy = null, $isHaving =
        array(), $limit = null, $offset = null, $orderBy = null, $order = null, $isQuotes = true;
    private $link, $connection, $config, $lastQuery, $lastError, $throwError = false;
    public $insertId, $clientFlags = 0, $newLink = true, $persistentConnection = false,
        $instantiateClass = 'stdClass';
    /**
     * Define all properties needed.
     * @return void
     */
    function __construct($connection = 'default') {
        $config         = Config::database();
        $this->config = $config[$connection];
        $this->connection = $connection;
    }
    /**
     * Throw the error instead handle it automaticly.
     * User should catch this error for there own purpose.
     *
     * @param bool $set
     * @return void
     */
    public function setThrowError($set = false) {
        $this->throwError = $set;
    }
    /**
     * Establish a new connection to mysql server
     *
     * @return string | boolean MySQL persistent link identifier on success, or FALSE on failure.
     */
    private function establishConnection() {
        $function = ($this->config['persistent']) ? 'mysql_pconnect' : 'mysql_connect';
        return $function($this->config['host'] . ':' . $this->config['port'], $this->
            config['user'], $this->config['password'], $this->newLink, $this->clientFlags);
    }
    /**
     * Inital for all process
     *
     * @return void
     */
    private function init() {
        if (is_null($this->link))
            $this->link = $this->establishConnection();
        try {
            if (!$this->link)
                throw new RunException('Unable connet to database in <strong>' . $this->
                    connection . '</strong> connection.');
        }
        catch (RunException $e) {
            RunException::outputError($e->getMessage());
        }
        $collation_query = '';
        if (!empty($this->config['charset'])) {
            $collation_query = "SET NAMES '" . $this->config['charset'] . "'";
            if (!empty($this->config['collate']))
                $collation_query .= " COLLATE '" . $this->config['collate'] . "'";
        }
        if (!empty($collation_query))
            $this->query($collation_query);
        $this->selectDb($this->config['database']);
    }
    /**
     * Select the databse
     *
     * @return void
     */
    private function selectDb($dbname) {
        if (is_null($this->link))
            $this->init();
        try {
            if (!@mysql_select_db($dbname, $this->link))
                throw new RunException('Unable to select database in <strong>' . $this->
                    connection . '</strong> connection.');
        }
        catch (RunException $e) {
            RunException::outputError($e->getMessage());
        }
    }
   
    /**
     * Start transaction.
     *
     * @return void
     */
    public function begin() {
        $this->query("START TRANSACTION");
        $this->query("BEGIN");
    }
    /**
     * Commit transaction.
     *
     * @return void
     */
    public function commit() {
        $this->query("COMMIT");
    }
    /**
     * Rollback transaction.
     *
     * @return void
     */
    public function rollback() {
        $this->query("ROLLBACK");
    }
    /**
     * Escape all unescaped string
     *
     * @param string $string
     * @return void
     */
    public function escape($string) {
        if (is_null($this->link))
            $this->init();
        return mysql_real_escape_string($string, $this->link);
    }
    /**
     * Main function for querying to database
     *
     * @param $query The SQL querey statement
     * @return string|objet Return the resource id of query
     */
    public function query($sql) {
        if (is_null($this->link))
            $this->init();
        $query = mysql_query($sql, $this->link);
        $this->lastQuery = $sql;
        if ($this->lastError = mysql_error($this->link)) {
            if ($this->throwError) {
                throw new \Exception($this->lastError);
            } else {
                $this->printError();
                return false;
            }
        }
        return $query;
    }
   
   
    /**
     * Get value directly from single field. Previusly called get_var().
     *
     * @since Version 0.3.1
     * @param string @query
     * @return string|int Depen on it record value.
     */
    public function getVar($query = null) {
        if (is_null($query))
            $query = $this->command();
        $result = $this->row($query);
        $key = array_keys(get_object_vars($result));
        return $result->$key[0];
    }
    /**
     * Get multiple records
     *
     * @param string $query The sql query
     * @param string $type return data type option. the default is "object"
     */
    public function results($query, $type = 'object') {
        if (is_null($query))
            $query = $this->command();
        $result = $this->query($query);
        while ($row = mysql_fetch_object($result, $this->instantiateClass)) {
            if ($type == 'array')
                $return[] = (array )$row;
            else
                $return[] = $row;
        }
        mysql_free_result($result);
        if (!isset($return))
            return false;
        return $return;
    }
    /**
     * Get single record
     *
     * @param string $query The sql query
     * @param string $type return data type option. the default is "object"
     */
    public function row($query, $type = 'object') {
        if (is_null($query))
            $query = $this->command();
        if (is_null($this->link))
            $this->init();
        $result = $this->query($query);
        $return = mysql_fetch_object($result, $this->instantiateClass);
        if ($type == 'array')
            return (array )$return;
        else
            return $return;
    }
    
    /**
     * Get the id form last insert
     *
     * @return int
     */
    public function insertId() {
        return @mysql_insert_id($this->link);
    }
        /**
     * Print the error
     *
     * @return string
     */
    private function printError() {
        if ($caller = RunException::getErrorCaller(5))
            $error_str = sprintf('Database error %1$s for query %2$s made by %3$s', $this->
                lastError, $this->lastQuery, $caller);
        else
            $error_str = sprintf('Database error %1$s for query %2$s', $this->lastError, $this->
                lastQuery);
        RunException::outputError($error_str);
    }
    /**
     * Get this db version
     *
     * @return void
     */
    public function version() {
        return $this->getVar("SELECT version() AS version");
    }
    /**
     * Close db connection
     *
     * @return void
     */
    public function close() {
        mysql_close($this->link);
    }
}
